package truerefactor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SpringLayout;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import truerefactor.input.CPPGraphParser;
import truerefactor.input.JavaGraphParser;
import truerefactor.ui.Splash;

/**
 * TrueRefactorGUI - A GUI used to control and observer the refactoring process
 * 
 * @author Isaac Griffith
 */
public class TrueRefactorGUI {

    /**
     * Spawns the thread in which the GA operates
     */
    private ExecutorService service;
    /**
     * The actual window for the UI
     */
    private JFrame frmTrueRefactor;
    /**
     * the textfield storing the directory of the codebase root
     */
    private JTextField tfCodeDir;
    /**
     * the textfield storing the directory to output code
     */
    private JTextField tfUMLOutDir;
    /**
     * the textfield storing the name of the report file to be generated
     */
    private JTextField tfResultsReport;
    /**
     * the combo box selecting the language to be used
     */
    private JComboBox languageCombo;
    /**
     * the associated system controller
     */
    private SystemController control = new SystemController(this);
    /**
     * the reset action to be used to reset the settings for refactoring
     */
    private final Action reset = new ResetAction(this);
    /**
     * the process action to start the process of refactoring
     */
    private final Action process = new ProcessAction(this, control);
    /**
     * the action used to browse for the code directory
     */
    private Action browseCode;
    /**
     * the action used to browse for the storage location for generated UML
     */
    private Action browseUML;
    /**
     * the action used to browse for the storage location of the generated results files
     */
    private Action browseResults;
    /**
     * checkbox determining if a specific name for results is to be used
     */
    private JCheckBox chckbxReportResults;
    /**
     * button used to browse for the generated report storage location
     */
    private JButton btnReportBrowse;
    /**
     * button used to browse for the generated UML storage location
     */
    private JButton btnUMLBrowse;
    /**
     * button used to browse for the generated code storage location
     */
    private JButton btnCodeBrowse;
    /**
     * file label for the report panel
     */
    private JLabel lblFile;
    /**
     * the known refactorings list
     */
    private JList lstRefactorings;
    /**
     * the known code smells list
     */
    private JList lstSmells;
    /**
     * the known metrics list
     */
    private JList lstMetrics;
    /**
     * action used to stop the refactoring process
     */
    private final Action stopProcess = new StopAction();
    /**
     * text area holding the log cache to be displayed to the user
     */
    private JTextArea txtLog;
    /**
     * spinner allowing proper selection of maximum log entries to be cached
     */
    private JSpinner spinMaxLog;
    /**
     * spinner allowing proper selection of smell factor
     */
    private JSpinner spinSmellFactor;
    /**
     * spinner allowing proper selection of population size
     */
    private JSpinner spinPopSize;
    /**
     * spinner allowing proper selection of mutation rate
     */
    private JSpinner spinMutationRate;
    /**
     * spinner allowing proper selection of max iteration size of the GA
     */
    private JSpinner spinGenerations;
    /**
     * label for the log
     */
    private JLabel lblMaxLog;
    /**
     * label for smell factor
     */
    private JLabel lblSmellFactor;
    /**
     * label for population size
     */
    private JLabel lblPopSize;
    /**
     * lable for mutation rate
     */
    private JLabel lblMutationRate;
    /**
     * label for max generations
     */
    private JLabel lblGenerations;

    /**
     * Launch the application.
     */
    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable() {
            public void run()
            {
                try
                {
                    TrueRefactorGUI window = new TrueRefactorGUI();
                    Splash splash = new Splash(window.frmTrueRefactor, 3000);
                    // window.frmTrueRefactor.setVisible(true);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public TrueRefactorGUI()
    {
        try
        {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        }
        catch (ClassNotFoundException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (InstantiationException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IllegalAccessException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (UnsupportedLookAndFeelException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        initialize();
        updateListInfo();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize()
    {
        frmTrueRefactor = new JFrame();
        frmTrueRefactor.setTitle("TrueRefactor");
        frmTrueRefactor.setSize(1400, 800);

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        frmTrueRefactor.setLocation((int) (screenSize.getWidth() - frmTrueRefactor.getWidth()) / 2 - 1,
                (int) (screenSize.getHeight() - frmTrueRefactor.getHeight()) / 2 - 1);
        // frmTrueRefactor.setBounds(100, 100, 1280, 1024);
        frmTrueRefactor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmTrueRefactor.getContentPane().setLayout(null);

        JPanel eastPanels = new JPanel();
        eastPanels.setBounds(1102, 0, 274, 753);
        frmTrueRefactor.getContentPane().add(eastPanels);
        eastPanels.setLayout(new GridLayout(3, 1, 0, 0));

        JPanel refactoringsPnl = new JPanel();
        refactoringsPnl.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Refactorings",
                TitledBorder.LEADING, TitledBorder.TOP, null, null));
        eastPanels.add(refactoringsPnl);
        refactoringsPnl.setLayout(new BorderLayout(0, 0));

        JScrollPane refactoringsScrPn = new JScrollPane();
        refactoringsPnl.add(refactoringsScrPn, BorderLayout.CENTER);

        lstRefactorings = new JList();
        lstRefactorings.setFocusable(false);
        lstRefactorings.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        refactoringsScrPn.setViewportView(lstRefactorings);

        JPanel smellsPnl = new JPanel();
        smellsPnl.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Code Smells",
                TitledBorder.LEADING, TitledBorder.TOP, null, null));
        eastPanels.add(smellsPnl);
        smellsPnl.setLayout(new BorderLayout(0, 0));

        JScrollPane smellsScrPn = new JScrollPane();
        smellsPnl.add(smellsScrPn, BorderLayout.CENTER);

        lstSmells = new JList();
        lstSmells.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        smellsScrPn.setViewportView(lstSmells);

        JPanel metricsPnl = new JPanel();
        metricsPnl.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Metrics",
                TitledBorder.LEADING, TitledBorder.TOP, null, null));
        eastPanels.add(metricsPnl);
        metricsPnl.setLayout(new BorderLayout(0, 0));

        JScrollPane metricsScrPn = new JScrollPane();
        metricsPnl.add(metricsScrPn, BorderLayout.CENTER);

        lstMetrics = new JList();
        lstMetrics.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        metricsScrPn.setViewportView(lstMetrics);

        JPanel westPanels = new JPanel();
        westPanels.setBounds(0, 0, 282, 753);
        frmTrueRefactor.getContentPane().add(westPanels);
        westPanels.setLayout(null);

        JPanel settingsPnl = new JPanel();
        settingsPnl.setBounds(0, 6, 282, 232);
        settingsPnl.setPreferredSize(new Dimension(10, 270));
        settingsPnl.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Settings",
                TitledBorder.LEADING, TitledBorder.TOP, null, null));
        westPanels.add(settingsPnl);
        SpringLayout sl_settingsPnl = new SpringLayout();
        settingsPnl.setLayout(sl_settingsPnl);

        Box codeBox = Box.createHorizontalBox();
        sl_settingsPnl.putConstraint(SpringLayout.NORTH, codeBox, 0, SpringLayout.NORTH, settingsPnl);
        settingsPnl.add(codeBox);

        Component horizontalStrut_10 = Box.createHorizontalStrut(20);
        horizontalStrut_10.setPreferredSize(new Dimension(10, 0));
        codeBox.add(horizontalStrut_10);

        JLabel lblCodeDirectory = new JLabel("Code Directory ");
        codeBox.add(lblCodeDirectory);

        Component horizontalStrut_6 = Box.createHorizontalStrut(20);
        horizontalStrut_6.setMinimumSize(new Dimension(10, 0));
        horizontalStrut_6.setPreferredSize(new Dimension(10, 0));
        codeBox.add(horizontalStrut_6);

        tfCodeDir = new JTextField();
        tfCodeDir.setToolTipText("The directory location of the code to be refactored.");
        codeBox.add(tfCodeDir);
        tfCodeDir.setColumns(10);

        Component horizontalGlue_1 = Box.createHorizontalGlue();
        codeBox.add(horizontalGlue_1);

        browseCode = new BrowseAction(frmTrueRefactor, tfCodeDir, true, false);

        btnCodeBrowse = new JButton("...");
        btnCodeBrowse.setAction(browseCode);
        codeBox.add(btnCodeBrowse);

        Box umlBox = Box.createHorizontalBox();
        sl_settingsPnl.putConstraint(SpringLayout.NORTH, umlBox, 6, SpringLayout.SOUTH, codeBox);
        sl_settingsPnl.putConstraint(SpringLayout.WEST, umlBox, 0, SpringLayout.WEST, codeBox);
        settingsPnl.add(umlBox);

        Component horizontalStrut_8 = Box.createHorizontalStrut(20);
        horizontalStrut_8.setPreferredSize(new Dimension(10, 0));
        umlBox.add(horizontalStrut_8);

        JLabel lblUmlOutput = new JLabel("UML Output Dir");
        sl_settingsPnl.putConstraint(SpringLayout.NORTH, lblUmlOutput, 6, SpringLayout.NORTH, settingsPnl);
        umlBox.add(lblUmlOutput);

        Component horizontalStrut_1 = Box.createHorizontalStrut(20);
        horizontalStrut_1.setPreferredSize(new Dimension(10, 0));
        horizontalStrut_1.setMinimumSize(new Dimension(10, 0));
        umlBox.add(horizontalStrut_1);

        tfUMLOutDir = new JTextField();
        tfUMLOutDir.setToolTipText("The location of the output directory for UML Output");
        umlBox.add(tfUMLOutDir);
        tfUMLOutDir.setColumns(10);

        Component horizontalGlue = Box.createHorizontalGlue();
        umlBox.add(horizontalGlue);

        browseUML = new BrowseAction(frmTrueRefactor, tfUMLOutDir, true, true);

        btnUMLBrowse = new JButton("...");
        btnUMLBrowse.setAction(browseUML);
        umlBox.add(btnUMLBrowse);

        Box reportBox = Box.createVerticalBox();
        sl_settingsPnl.putConstraint(SpringLayout.WEST, reportBox, 0, SpringLayout.WEST, codeBox);
        sl_settingsPnl.putConstraint(SpringLayout.EAST, reportBox, 0, SpringLayout.EAST, settingsPnl);
        reportBox.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
        settingsPnl.add(reportBox);

        Box horizontalBox_2 = Box.createHorizontalBox();
        horizontalBox_2.setAlignmentX(Component.RIGHT_ALIGNMENT);
        reportBox.add(horizontalBox_2);

        chckbxReportResults = new JCheckBox("Report Results");
        chckbxReportResults.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e)
            {
                boolean enabled = chckbxReportResults.isSelected();

                lblFile.setEnabled(enabled);
                tfResultsReport.setEnabled(enabled);
                btnReportBrowse.setEnabled(enabled);
            }
        });
        horizontalBox_2.add(chckbxReportResults);

        Component horizontalStrut_3 = Box.createHorizontalStrut(20);
        horizontalBox_2.add(horizontalStrut_3);

        Component horizontalStrut_2 = Box.createHorizontalStrut(20);
        horizontalBox_2.add(horizontalStrut_2);

        JLabel label_1 = new JLabel("                 ");
        horizontalBox_2.add(label_1);

        Component verticalStrut = Box.createVerticalStrut(10);
        reportBox.add(verticalStrut);

        Box horizontalBox_3 = Box.createHorizontalBox();
        reportBox.add(horizontalBox_3);

        Component horizontalStrut_4 = Box.createHorizontalStrut(20);
        horizontalBox_3.add(horizontalStrut_4);

        lblFile = new JLabel("Filename ");
        horizontalBox_3.add(lblFile);

        tfResultsReport = new JTextField();
        horizontalBox_3.add(tfResultsReport);
        tfResultsReport.setColumns(10);

        browseResults = new BrowseAction(frmTrueRefactor, tfResultsReport, false, true);

        btnReportBrowse = new JButton("...");
        btnReportBrowse.setAction(browseResults);
        horizontalBox_3.add(btnReportBrowse);

        Box languageBox = Box.createHorizontalBox();
        sl_settingsPnl.putConstraint(SpringLayout.NORTH, languageBox, 40, SpringLayout.SOUTH, codeBox);
        sl_settingsPnl.putConstraint(SpringLayout.WEST, languageBox, 0, SpringLayout.WEST, codeBox);
        sl_settingsPnl.putConstraint(SpringLayout.EAST, languageBox, 0, SpringLayout.EAST, settingsPnl);

        Component horizontalStrut_7 = Box.createHorizontalStrut(20);
        horizontalStrut_7.setPreferredSize(new Dimension(10, 0));
        umlBox.add(horizontalStrut_7);
        settingsPnl.add(languageBox);

        Component horizontalStrut_9 = Box.createHorizontalStrut(20);
        horizontalStrut_9.setMinimumSize(new Dimension(10, 0));
        horizontalStrut_9.setPreferredSize(new Dimension(10, 0));
        languageBox.add(horizontalStrut_9);

        JLabel lblLanguage = new JLabel("Language ");
        languageBox.add(lblLanguage);

        Component horizontalStrut_5 = Box.createHorizontalStrut(20);
        horizontalStrut_5.setPreferredSize(new Dimension(36, 0));
        languageBox.add(horizontalStrut_5);

        languageCombo = new JComboBox();
        languageCombo.setPreferredSize(new Dimension(25, 26));
        languageBox.add(languageCombo);
        languageCombo.addItem(JavaGraphParser.LANGUAGE);
        languageCombo.addItem(CPPGraphParser.LANGUAGE);

        Component horizontalStrut = Box.createHorizontalStrut(20);
        languageBox.add(horizontalStrut);
        horizontalStrut.setMinimumSize(new Dimension(15, 0));
        horizontalStrut.setPreferredSize(new Dimension(10, 0));

        JButton btnProcess = new JButton("Process");
        sl_settingsPnl.putConstraint(SpringLayout.SOUTH, reportBox, -6, SpringLayout.NORTH, btnProcess);
        sl_settingsPnl.putConstraint(SpringLayout.SOUTH, btnProcess, 0, SpringLayout.SOUTH, settingsPnl);
        sl_settingsPnl.putConstraint(SpringLayout.EAST, btnProcess, 0, SpringLayout.EAST, settingsPnl);
        btnProcess.setFont(new Font("SansSerif", Font.BOLD | Font.ITALIC, 12));
        btnProcess.setBackground(new Color(0, 204, 51));
        btnProcess.setAction(process);
        btnProcess.setMnemonic('P');
        settingsPnl.add(btnProcess);

        // JButton button = new JButton("New button");
        // button.setAction(action);
        // sl_settingsPnl.putConstraint(SprintLayout.SOUTH, separator, 6,
        // SprintLayout., c2)
        // sl_settingsPnl.putConstraint(SpringLayout.WEST, btnProcess, -6,
        // SpringLayout.WEST, settingsPnl);
        // sl_settingsPnl.putConstraint(SpringLayout.SOUTH, separator, -6,
        // SpringLayout.NORTH, button);
        // sl_settingsPnl.putConstraint(SpringLayout.EAST, button, -100,
        // SpringLayout.EAST, settingsPnl);
        // settingsPnl.add(button);

        JButton btnReset = new JButton("Reset");
        sl_settingsPnl.putConstraint(SpringLayout.WEST, btnReset, 0, SpringLayout.WEST, codeBox);

        Component horizontalStrut_14 = Box.createHorizontalStrut(20);
        horizontalStrut_14.setPreferredSize(new Dimension(10, 0));
        horizontalStrut_14.setMinimumSize(new Dimension(10, 0));
        codeBox.add(horizontalStrut_14);
        sl_settingsPnl.putConstraint(SpringLayout.SOUTH, btnReset, 0, SpringLayout.SOUTH, settingsPnl);
        btnReset.setAction(reset);
        btnReset.setMnemonic('R');
        settingsPnl.add(btnReset);

        JPanel panel_7 = new JPanel();
        panel_7.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Progress Log",
                TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panel_7.setBounds(286, 0, 821, 753);
        frmTrueRefactor.getContentPane().add(panel_7);
        panel_7.setLayout(new BorderLayout(0, 0));

        JScrollPane scrollPane_3 = new JScrollPane();
        scrollPane_3.setDoubleBuffered(true);
        scrollPane_3.setAutoscrolls(true);
        panel_7.add(scrollPane_3, BorderLayout.CENTER);

        txtLog = new JTextArea();
        txtLog.setAutoscrolls(true);
        txtLog.setDoubleBuffered(true);
        txtLog.setFont(new Font("Courier New", Font.PLAIN, 11));
        txtLog.setWrapStyleWord(true);
        scrollPane_3.setViewportView(txtLog);

        tfResultsReport.setEnabled(false);
        lblFile.setEnabled(false);

        JButton btnStop = new JButton("Stop");
        sl_settingsPnl.putConstraint(SpringLayout.SOUTH, btnStop, 0, SpringLayout.SOUTH, settingsPnl);
        sl_settingsPnl.putConstraint(SpringLayout.EAST, btnStop, -2, SpringLayout.WEST, btnProcess);
        btnStop.setFont(new Font("SansSerif", Font.BOLD | Font.ITALIC, 12));
        btnStop.setBackground(Color.RED);
        btnStop.setEnabled(false);
        btnStop.setMnemonic('S');
        btnStop.setAction(stopProcess);
        settingsPnl.add(btnStop);

        JPanel panel = new JPanel();
        panel.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "GA Configuration",
                TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panel.setBounds(0, 250, 282, 173);
        westPanels.add(panel);
        panel.setLayout(null);

        lblGenerations = new JLabel("Number of GA Generations");
        lblGenerations.setBounds(20, 27, 172, 16);
        panel.add(lblGenerations);

        lblMutationRate = new JLabel("Mutation Rate (%)");
        lblMutationRate.setBounds(20, 55, 172, 16);
        panel.add(lblMutationRate);

        lblPopSize = new JLabel("Population Size");
        lblPopSize.setBounds(20, 83, 172, 16);
        panel.add(lblPopSize);

        lblSmellFactor = new JLabel("Code Smell Elimination (%)");
        lblSmellFactor.setBounds(20, 111, 172, 16);
        panel.add(lblSmellFactor);

        lblMaxLog = new JLabel("Max number of results shown");
        lblMaxLog.setBounds(20, 139, 172, 16);
        panel.add(lblMaxLog);

        spinGenerations = new JSpinner();
        lblGenerations.setLabelFor(spinGenerations);
        spinGenerations.setModel(new SpinnerNumberModel(1, 1, 10000, 10));
        spinGenerations.setBounds(204, 21, 72, 28);
        panel.add(spinGenerations);

        spinMutationRate = new JSpinner();
        lblMutationRate.setLabelFor(spinMutationRate);
        spinMutationRate.setModel(new SpinnerNumberModel(0, 0, 100, 1));
        spinMutationRate.setBounds(204, 49, 72, 28);
        panel.add(spinMutationRate);

        spinPopSize = new JSpinner();
        lblPopSize.setLabelFor(spinPopSize);
        spinPopSize.setModel(new SpinnerNumberModel(10, 10, 50, 1));
        spinPopSize.setBounds(204, 77, 72, 28);
        panel.add(spinPopSize);

        spinSmellFactor = new JSpinner();
        lblSmellFactor.setLabelFor(spinSmellFactor);
        spinSmellFactor.setModel(new SpinnerNumberModel(50, 0, 100, 1));
        spinSmellFactor.setBounds(204, 105, 72, 28);
        panel.add(spinSmellFactor);

        spinMaxLog = new JSpinner();
        lblMaxLog.setLabelFor(spinMaxLog);
        spinMaxLog.setModel(new SpinnerNumberModel(5, 5, 100, 1));
        spinMaxLog.setBounds(204, 133, 72, 28);
        panel.add(spinMaxLog);

        browseResults.setEnabled(false);
        stopProcess.setEnabled(false);
    }

    /**
     * Updates the information contained in the lists
     */
    private void updateListInfo()
    {
        List<String> metrics = control.getAvailableMetrics();
        List<String> smells = control.getAvailableCodeSmells();
        List<String> refactorings = control.getAvailableRefactorings();

        lstMetrics.setListData(metrics.toArray(new String[0]));
        lstSmells.setListData(smells.toArray(new String[0]));
        lstRefactorings.setListData(refactorings.toArray(new String[0]));
    }

    /**
     * Enables/disables the contents of the settings panel based on the provided
     * flag.
     * 
     * @param enable
     *            Flag to enable or disable the settings panel
     */
    private void settingsPanelEnable(boolean enable)
    {
        languageCombo.setEnabled(enable);
        tfCodeDir.setEnabled(enable);
        tfUMLOutDir.setEnabled(enable);
        tfResultsReport.setEnabled(enable);
        browseCode.setEnabled(enable);
        browseResults.setEnabled(enable);
        browseUML.setEnabled(enable);
        chckbxReportResults.setEnabled(enable);
        stopProcess.setEnabled(!enable);
        process.setEnabled(enable);
    }

    /**
     * Method to verify that the entered data is valid
     * 
     * @return true if all data passes the smoke test, false otherwise
     */
    private boolean checkData()
    {
        boolean isGood = true;

        if (languageCombo.getSelectedIndex() < 0)
            isGood = false;
        if (tfCodeDir.getText().length() <= 0)
            isGood = false;
        if (tfUMLOutDir.getText().length() <= 0)
            isGood = false;
        if (chckbxReportResults.isSelected() && tfResultsReport.getText().length() <= 0)
            isGood = false;

        process.setEnabled(isGood);
        return isGood;
    }

    /**
     * Adds the provided text to the logging window
     * 
     * @param log
     *            text to append
     */
    public synchronized void addToLogger(String log)
    {
        txtLog.append(log);
        // txtLog.setText(txtLog.getText() + log);
        // System.out.println(log);
    }

    /**
     * Returns the entire text currently held by the logger
     * 
     * @return logger text
     */
    public synchronized String getLog()
    {
        return txtLog.getText();
    }

    /**
     * Sets the current text of the logging pane to be the provided string
     * 
     * @param log
     *            new contents of the logger
     */
    public synchronized void setLog(String log)
    {
        txtLog.setText(log);
    }

    /**
     * Returns the current value of the mutation rate as a value between 0.0 and
     * 1.0 (inclusive)
     * 
     * @return the mutation rate for the Genetic Algorithm
     */
    public double getMutationRate()
    {
        double value = (double) ((Integer) spinMutationRate.getValue()) / 100;
        return value;
    }

    /**
     * Returns the current value for population size
     * 
     * @return population size for the Genetic Algorithm
     */
    public int getPopSize()
    {
        return (Integer) spinPopSize.getValue();
    }

    /**
     * Returns the smell factor, which is the percentage of code smells to
     * remove as a goal of the Genetic Algorithm
     * 
     * @return the factor influencing selection pressure for the GA based on
     *         removed code smells
     */
    public double getSmellFactor()
    {
        double value = (double) ((Integer) spinSmellFactor.getValue()) / 100;
        return value;
    }

    /**
     * Returns the maximum number of generations that the log will cache before
     * writing to a file
     * 
     * @return max number of generations to be logged by the GA
     */
    public int getMaxLogLength()
    {
        return (Integer) spinMaxLog.getValue();
    }

    /**
     * @return max number of iterations of the GA
     */
    public int getMaxIterations()
    {
        return (Integer) spinGenerations.getValue();
    }

    /**
     * ResetAction - Class representing the action of reseting the settings and
     * parameters of the Genetic Algorithm
     * 
     * @author Isaac
     */
    @SuppressWarnings("serial")
    private class ResetAction extends AbstractAction {

        /**
         * The TrueRefactorGUI parent for this object
         */
        private TrueRefactorGUI gui = null;

        /**
         * Constructs a new ResetAction object associated with the provided
         * TrueRefactorGUI
         * 
         * @param gui
         *            parent of this action
         */
        public ResetAction(TrueRefactorGUI gui)
        {
            this.gui = gui;
            putValue(NAME, "Reset");
            putValue(SHORT_DESCRIPTION, "Some short description");
        }

        /*
         * (non-Javadoc)
         * @see
         * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent
         * )
         */
        public void actionPerformed(ActionEvent e)
        {
            gui.languageCombo.setSelectedIndex(0);
            gui.tfCodeDir.setText("");
            gui.tfUMLOutDir.setText("");
            gui.tfResultsReport.setText("");

            if (service != null)
            {
                service.shutdownNow();
                settingsPanelEnable(true);
            }
        }
    }

    /**
     * ProcessAction - Class representing the action of beginning the
     * refactoring process
     * 
     * @author Isaac
     */
    private class ProcessAction extends AbstractAction {

        /**
         * The parent TrueRefactorGUI of this action
         */
        private TrueRefactorGUI gui = null;
        /**
         * The SystemController connected to the parent UI
         */
        private SystemController control = null;

        /**
         * Constructs a new ProcessAction Object associated with the provided
         * TrueRefactorGUI and SystemController
         * 
         * @param gui
         *            parent UI
         * @param control
         *            associated SystemController
         */
        public ProcessAction(TrueRefactorGUI gui, SystemController control)
        {
            this.gui = gui;
            this.control = control;
            putValue(NAME, "Process");
            putValue(SHORT_DESCRIPTION, "Begin the refactoring process.");
        }

        /*
         * (non-Javadoc)
         * @see
         * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent
         * )
         */
        public void actionPerformed(ActionEvent e)
        {
            txtLog.setText("");
            service = Executors.newSingleThreadExecutor();
            control.setLanguage(gui.languageCombo.getItemAt(gui.languageCombo.getSelectedIndex()).toString());
            control.setCodeInLoc(gui.tfCodeDir.getText());
            control.setUmlOutLoc(gui.tfUMLOutDir.getText());
            control.setLogFileLoc(gui.tfResultsReport.getText());

            settingsPanelEnable(false);

            // control.process();
            service.execute(control);
            service.shutdown();
        }
    }

    /**
     * BrowseAction - A class used to handle the event when the user presses a
     * button to browse for a file/folder on the system
     * 
     * @author Isaac
     */
    private class BrowseAction extends AbstractAction {

        /**
         * The JTextField to hold the found folder/file
         */
        private JTextField field;
        /**
         * The flag determining if we are browsing for a directory or file
         */
        private boolean dir;
        /**
         * The FileChooser which will be used to navigate to the location
         */
        private JFileChooser jfcFile;
        /**
         * The flag determining whether a save is to occur or not (changing the
         * appearance of the file chooser's buttons)
         */
        private boolean save;
        /**
         * The parent JFrame to be used in construction of the JFileChooser
         */
        private JFrame parent;

        /**
         * Constructs a new BrowseAction object associated with the provided
         * parent, field, and with the appropriate flags set.
         * 
         * @param parent
         *            Parent Frame for the JFileChooser
         * @param field
         *            Field to store the selected value
         * @param dir
         *            if True we are searching for a directory, else we are
         *            looking for a file
         * @param save
         *            true if we want the value of the main action button in the
         *            file chooser to say save
         */
        public BrowseAction(JFrame parent, JTextField field, boolean dir, boolean save)
        {
            this.field = field;
            this.dir = dir;
            this.save = save;
            this.parent = parent;

            jfcFile = new JFileChooser();
            jfcFile.setMultiSelectionEnabled(false);

            if (dir)
            {
                jfcFile.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            }

            putValue(NAME, "...");
            putValue(SHORT_DESCRIPTION, "Select file location...");
        }

        /*
         * (non-Javadoc)
         * @see
         * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent
         * )
         */
        public void actionPerformed(ActionEvent e)
        {
            if (save)
            {
                int option = jfcFile.showSaveDialog(parent);
                if (option == JFileChooser.APPROVE_OPTION)
                {
                    field.setText(((jfcFile.getSelectedFile() != null) ? jfcFile.getSelectedFile().getAbsolutePath()
                                                                      : ""));
                }
            }
            else
            {
                int option = jfcFile.showOpenDialog(parent);
                if (option == JFileChooser.APPROVE_OPTION)
                {
                    field.setText(((jfcFile.getSelectedFile() != null) ? jfcFile.getSelectedFile().getAbsolutePath()
                                                                      : ""));
                }
            }
        }
    }

    /**
     * StopAction - A class representing the action of the Stop Button, which
     * handles the user's desire to cancel the GA and reset the system
     * 
     * @author Isaac
     */
    private class StopAction extends AbstractAction {

        /**
         * Constructs a new StopAction object
         */
        public StopAction()
        {
            putValue(NAME, "Stop");
            putValue(SHORT_DESCRIPTION, "Stops the refactoring system");
        }

        /*
         * (non-Javadoc)
         * @see
         * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent
         * )
         */
        public void actionPerformed(ActionEvent e)
        {
            service.shutdownNow();
            settingsPanelEnable(true);
        }
    }
}
